// --------------------------------------------------------------------------------------------------------------------
// <copyright file="Helper.cs" company="">
//   
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
namespace ExecutionTool.Common
{
    using System;
    using System.Diagnostics;
    using System.IO;
    using System.Security.Cryptography;
    using System.Text;

    using Microsoft.Practices.EnterpriseLibrary.Logging;
    using Microsoft.Win32;

    public static class Helper
    {
        #region Constants

        private const string DefaultLogCategory = "General";

        private const string SystemEventLogCategory = "EventLog";

        #endregion

        #region Public Methods and Operators

        public static void CheckForNull(object target, string paramName)
        {
            if (target == null)
            {
                throw new ArgumentException("Null is not allowed.", paramName);
            }
        }

        public static string Decrypt(string cipher)
        {
            if (string.IsNullOrWhiteSpace(cipher))
            {
                return string.Empty;
            }

            var clear = TripleDesDecryption(cipher, GetProvider());
            return clear;
        }

        public static string Encrypt(string clear)
        {
            if (string.IsNullOrWhiteSpace(clear))
            {
                return string.Empty;
            }

            var ciphered = TripleDesEncryption(clear, GetProvider());
            return ciphered;
        }

        public static void Log(this LogWriter logger, string message, TraceEventType severity, int eventId = 0)
        {
            if (logger.IsLoggingEnabled())
            {
                if (eventId > 0)
                {
                    logger.Write(message, new[] { DefaultLogCategory, SystemEventLogCategory }, 0, eventId, severity);
                }
                else
                {
                    logger.Write(message, DefaultLogCategory, 0, eventId, severity);
                }
            }
        }

        public static void LogError(this LogWriter logger, string message, int errorCode = 0)
        {
            Log(logger, message, TraceEventType.Error, errorCode);
        }

        public static void LogInformation(this LogWriter logger, string message, int eventId = 0)
        {
            Log(logger, message, TraceEventType.Information, eventId);
        }

        public static void LogVerbose(this LogWriter logger, string message)
        {
            Log(logger, message, TraceEventType.Verbose);
        }

        public static void LogWarning(this LogWriter logger, string message, int errorCode = 0)
        {
            Log(logger, message, TraceEventType.Warning, errorCode);
        }

        public static string TripleDesDecryption(string dataToDecrypt, TripleDESCryptoServiceProvider provider)
        {
            var bytes = Convert.FromBase64String(dataToDecrypt);

            using (provider)
            {
                using (var ms = new MemoryStream())
                using (var decryptor = provider.CreateDecryptor())
                using (var cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Write))
                {
                    cs.Write(bytes, 0, bytes.Length);
                    cs.FlushFinalBlock();
                    var clear = ms.ToArray();
                    return Encoding.Unicode.GetString(clear);
                }
            }
        }

        public static string TripleDesEncryption(string dataToEncrypt, TripleDESCryptoServiceProvider provider)
        {
            var bytes = Encoding.Unicode.GetBytes(dataToEncrypt);

            using (provider)
            {
                using (var ms = new MemoryStream())
                using (var encryptor = provider.CreateEncryptor())
                using (var cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
                {
                    cs.Write(bytes, 0, bytes.Length);
                    cs.FlushFinalBlock();
                    var cipher = ms.ToArray();
                    return Convert.ToBase64String(cipher);
                }
            }
        }

        #endregion

        #region Methods

        private static TripleDESCryptoServiceProvider GetProvider()
        {
            var on64 = IntPtr.Size == 8;
            var regkey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, on64 ? RegistryView.Registry64 : RegistryView.Registry32);

            const string KeyPath = @"Software\Microsoft\Windows NT\CurrentVersion";
            var subregkey = regkey.OpenSubKey(KeyPath);

            if (subregkey == null)
            {
                throw new Exception("Registry key not found.");
            }

            var pid = subregkey.GetValue("ProductId").ToString();
            const string Salt = "Hey, this is not the secret!";
            var pidBytes = Encoding.Unicode.GetBytes(pid);
            var saltBytes = Encoding.Unicode.GetBytes(Salt);

            var pdb = new PasswordDeriveBytes(pidBytes, saltBytes);
            var iv = new byte[] { 11, 165, 113, 5, 100, 245, 80, 2 };
            var key = pdb.CryptDeriveKey("TripleDES", "SHA1", 192, iv);
            var provider = new TripleDESCryptoServiceProvider { Key = key, IV = iv };

            return provider;
        }

        #endregion
    }
}
